/*
	Copyright 2006 Brano Kemen

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*
 * Include the core server components.
 */

#include <string.h>

#include "apachefix.h"
#include <httpd.h>
#include <http_config.h>
#include <util_filter.h>
#include <apr_thread_proc.h>

#include "conf.h"

//thread key
apr_threadkey_t*    Gthr_data = 0;


/*
 * This module
 */
module AP_MODULE_DECLARE_DATA coid_module;


static int child_cleanup( void* data );

/*
static int mod_coid_method_quick_handler( request_rec *r, int lookup_uri )
{
	apr_socket_t *csd;

	conn_rec *conn = r->connection;
	csd = ((core_net_rec *)conn->input_filters->ctx)->client_socket;

	return OK;
}
*/

/*
 * This function is registered as a handler for HTTP methods and will
 * therefore be invoked for all GET requests (and others).  Regardless
 * of the request type, this function simply sends a message to
 * STDERR (which httpd redirects to logs/error_log).  A real module
 * would do *alot* more at this point.
 */
static int mod_coid_method_handler( request_rec *r )
{
	// Get the module configuration
	//modcoid_config *s_cfg = ap_get_module_config(r->server->module_config, &coid_module);
    void* d=0;
	int mode = 0;

	if( r->uri != NULL && strlen(r->uri) > 6 && strncmp(r->uri, "/soap/", 6) == 0) {
		mode = 1;
	}
	else if( r->args != NULL && strlen(r->args) >= 5 && strncmp(r->args, "coid-", 5) != 0) {
		mode = 2;
	} else {
        return DECLINED;
	}

    apr_threadkey_private_get( &d, Gthr_data );
    if(!d) {
        d = coid_thr_data_create();
        apr_threadkey_private_set( d, Gthr_data );
        apr_pool_cleanup_register( r->server->process->pconf, d, child_cleanup, apr_pool_cleanup_null );
    }

    return coid_process_req(
		r, (CoidConfig*)ap_get_module_config( r->server->module_config, &coid_module ), d, mode);
}

static int child_cleanup( void* data )
{
    if(data)
        coid_thr_data_destroy(data);

    return 0;
}

static void child_init( apr_pool_t *p, server_rec *s )
{
    CoidConfig* cfg;

    if( !Gthr_data )
        apr_threadkey_private_create( &Gthr_data, NULL, p );

    cfg = (CoidConfig*) ap_get_module_config( s->module_config, &coid_module );
    fprintf( stderr, "Initializing coid server, parameters:\n\tserver lib:\t%s\n\tworking dir:\t%s\n\tlistener port:\t%i\n",
        (cfg->libserver ? cfg->libserver : "<default>"),
        (cfg->workdir ? cfg->workdir : "<default>"),
        cfg->port );

	coid_init( cfg, p );
}

/*
 * This function is a callback and it declares what other functions
 * should be called for request processing and configuration requests.
 * This callback function declares the Handlers for other events.
 */
static void mod_coid_register_hooks (apr_pool_t *p)
{
    ap_hook_child_init( child_init, NULL, NULL, APR_HOOK_MIDDLE );
	ap_hook_handler( mod_coid_method_handler, NULL, NULL, APR_HOOK_REALLY_FIRST );
	//ap_hook_quick_handler( mod_coid_method_quick_handler, NULL, NULL, APR_HOOK_REALLY_FIRST );
}

static const char *set_modcoid_port(cmd_parms *parms, void *mconfig, const char *arg)
{
	// get the module configuration (this is the structure created by create_modcoid_config())
	CoidConfig *s_cfg = ap_get_module_config(parms->server->module_config, &coid_module);

	// make a duplicate of the argument's value using the command parameters pool.
    s_cfg->port = atoi(arg);
	return NULL;
}

static const char *set_modcoid_addr(cmd_parms *parms, void *mconfig, const char *arg)
{
	// get the module configuration (this is the structure created by create_modcoid_config())
	CoidConfig *s_cfg = ap_get_module_config(parms->server->module_config, &coid_module);

	// make a duplicate of the argument's value using the command parameters pool.
    s_cfg->rempath = arg;
	return NULL;
}

static const char *set_modcoid_soapgw(cmd_parms *parms, void *mconfig, const char *arg)
{
	// get the module configuration (this is the structure created by create_modcoid_config())
	CoidConfig *s_cfg = ap_get_module_config(parms->server->module_config, &coid_module);

	// make a duplicate of the argument's value using the command parameters pool.
	s_cfg->soapgw = arg;

	return NULL;
}

/**
 * A declaration of the configuration directives that are supported by this module.
 */
static const command_rec mod_coid_cmds[] =
{
	AP_INIT_TAKE1(
		"CoidPort",
		set_modcoid_port,
		NULL,
		RSRC_CONF,
        "CoidPort <int> -- override the coid listener port number, either the default one (55099) or the one from dev.conf"
	),
	AP_INIT_TAKE1(
		"CoidServer",
		set_modcoid_addr,
		NULL,
		RSRC_CONF,
        "CoidPort <int> -- coid server to connect to, used when not spawning coid server from apache"
	),
	AP_INIT_TAKE1(
	"soap_gw",
	set_modcoid_soapgw,
	NULL,
	RSRC_CONF,
	"soap_gw <string> -- coid server SOAP gateway"
	),
	{NULL}
};

/**
 * Creates the per-server configuration records.
 */
static void *create_modcoid_config(apr_pool_t *p, server_rec *s)
{
    CoidConfig *newcfg;
	newcfg = (CoidConfig *) apr_pcalloc(p, sizeof(CoidConfig));

    //default values
	newcfg->port = 0;
    newcfg->libserver = 0;
    newcfg->workdir = 0;
    newcfg->rempath = "localhost";

	// return the new server configuration structure.
	return (void *) newcfg;
}

static void *merge_modcoid_config( apr_pool_t *p, void* base, void* add )
{
    CoidConfig *pcfg, *ncfg;
    pcfg = (CoidConfig*)base;
    ncfg = (CoidConfig*)add;

	return (void *)add;
}

/*
 * Declare and populate the module's data structure.  The
 * name of this structure ('coid_module') is important - it
 * must match the name of the module.  This structure is the
 * only "glue" between the httpd core and the module.
 */
module AP_MODULE_DECLARE_DATA coid_module =
{
	STANDARD20_MODULE_STUFF, // standard stuff; no need to mess with this.
	NULL, // create per-directory configuration structures - we do not.
	NULL, // merge per-directory - no need to merge if we are not creating anything.
	create_modcoid_config, // create per-server configuration structures.
	merge_modcoid_config, // merge per-server configuration structures.
	mod_coid_cmds, // configuration directive handlers
	mod_coid_register_hooks, // request handlers
};
